<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<style type="text/css" media="screen">
			html, body, canvas {
				margin: 0;
				padding: 0;
				overflow: hidden;
			}
		</style>
		<script type="text/javascript" charset="utf-8">
			(function(){
				//global vars
				var canvas;
				var context;

				var WIDTH = 800;
				var HEIGHT = 600;

				//class definition
				Ann = function(rows, cols){
					this.rows = rows;
					this.cols = cols;
					this.neurons = [];
					this.learnCount = 1;
					this.learningRate = 300;
					this.winner ={row: null, col: null};

					for(var i=0; i<rows; i++){
						this.neurons.push([]);
						for(var j=0; j<cols; j++){
							this.neurons[i].push(new Neuron(i/rows*HEIGHT, j/cols*WIDTH));
						}
					}
				}

				Neuron = function(x, y){
					this.x = Math.floor(Math.random()*WIDTH);
					this.y = Math.floor(Math.random()*HEIGHT);
					//this.x = x;
					//this.y = y;
					this.distance = null;
				}

				Ann.prototype.learn = function(x, y){
					//calculate distance
					var minDistance = null;

					for(var i in this.neurons){
						i = parseInt(i);
						for(var j in this.neurons[i]){
							j = parseInt(j);
							var neuron = this.neurons[i][j];
							var distance = Math.sqrt(Math.pow(x-neuron.x,2) + Math.pow(y-neuron.y,2));
							if(distance < minDistance || minDistance == null){
								minDistance = distance;
								this.winner.row = i;
								this.winner.col = j;
							}
						}
					}
					this.adjust(x, y);
				}

				Ann.prototype.adjust = function(x, y){
					this.learnCount += 1;
					for(var i in this.neurons){
						i = parseInt(i);
						for(var j in this.neurons[i]){
							j = parseInt(j);
							var neuron = this.neurons[i][j];
							var distance = (Math.pow(this.winner.row-i, 2) + Math.pow(this.winner.col-j, 2))/this.rows*this.cols + 1;
							var diffX = x - neuron.x;
							var diffY = y - neuron.y;

							var deltaX = diffX / distance / Math.log(this.learnCount);
							var deltaY = diffY / distance / Math.log(this.learnCount);

							neuron.x += deltaX;
							neuron.y += deltaY;
						}
					}
				}

				Ann.prototype.draw = function(){
					context.save();

					for(var i in this.neurons){
						//i is string...
						i = parseInt(i);
						for(var j in this.neurons[i]){
							//j also string...
							j = parseInt(j);
							var neuron = this.neurons[i][j];

							//draw point
							if(i == this.winner.row && j == this.winner.col){
								context.fillStyle = "red";
								var size = 10;
							}else{
								context.fillStyle = "black";
								var size = 3;
							}
							context.beginPath();
							context.arc(neuron.x, neuron.y, size, 0, Math.PI*2, false);
							context.closePath();
							context.fill();

							//draw line to right, bottom
							context.strokeStyle = "black";
							//bottom
							if(i < this.neurons.length-1){
								var nextNeuron = this.neurons[i+1][j];
								context.beginPath();
								context.moveTo(neuron.x, neuron.y);
								context.lineTo(nextNeuron.x, nextNeuron.y);
								context.closePath();
								context.stroke();
							}
							//right
							if(j < this.neurons[i].length-1){
								var nextNeuron = this.neurons[i][j+1];
								context.beginPath();
								context.moveTo(neuron.x, neuron.y);
								context.lineTo(nextNeuron.x, nextNeuron.y);
								context.closePath();
								context.stroke();
							}

						}
					}

					context.restore();
				}

				canvasApp = function(){
					canvas = document.querySelector('canvas');
					context = canvas.getContext('2d');

					WIDTH = window.innerWidth;
					HEIGHT = window.innerHeight;

					canvas.width = WIDTH;
					canvas.height = HEIGHT;

					var ann = new Ann(20,20);

					gameLoop = function(){
						context.fillStyle = "white";
						context.fillRect(0, 0, WIDTH, HEIGHT);

						var x = Math.floor(Math.random()*WIDTH);
						var y = Math.floor(Math.random()*HEIGHT);

						context.fillStyle = "orange";
						context.beginPath();
						context.arc(x, y, 5, 0, Math.PI*2);
						context.closePath();
						context.fill();

						ann.learn(x, y);
						ann.draw();
					}

					setInterval(gameLoop, 0);
				}
				window.addEventListener('load', canvasApp, false);
			})();
		</script>
		<title>Som</title>
	</head>
	<body>
		<canvas></canvas>
	</body>
</html>
